<script setup> 的優點
<script setup> 效能比較好<script setup>太好用,不知道什麼時候需要用 <script>
在 Vue 3 Composition API 的中,寫法上主要分成 <script>(+setup()) 和 <script setup> 兩種,核心概念相同,後者是前者的語法糖,相當好吃,只能說...「曾經滄海難為水」(?),連官方也推推。
既然如此,那...為什麼還需要 <script>?
今天就一起來了解。
<script setup> 的優點
<script>
註:不包含兩者基礎語法的完整比較
<script setup> 的優點官方推薦使用這個語法,提到他比起一般的 script 寫法多了以下優點:
- 更少的样板内容,更简洁的代码。
- 能够使用纯 TypeScript 声明 props 和自定义事件。
- 更好的运行时性能 (其模板会被编译成同一作用域内的渲染函数,避免了渲染上下文代理对象)。
- 更好的 IDE 类型推导性能 (减少了语言服务器从代码中抽取类型的工作)。
今天的內容會著重在第一點和第四點。
在能使用 <script setup> 正式推出之前,在 <script> 必須這樣寫。
在 setup() 裡定義會用到的變數、函式、計算屬性 (computed) 等等,並將模板上要用到的變數 return 出來。
<script><script>
    import { ref } from 'vue'
    export default {
      setup() {
        const count = ref(1)
        const increaseCount = () => {
          count.value++
        }
        return {
            count,
            increase
        }
      }
    }
</script>
<script setup>透過在 <script> 加上 setup 的屬性,Vue 會幫開發者將裡面的邏輯,包到 setup() 內,並將所有 top-level binding 自動暴露給模板。
<script setup>
    import { ref } from 'vue'
    const count = ref(1)
    const increaseCount = () => {
      count.value++
    }
</script>
直接省略了 6+n 行程式碼,不用一直重複寫:
export default {
    setup(){
        return {
            //暴露屬性給模板使用 +n 行
        }
    }
}

根據官方文件,<script setup>具有「更好的运行时性能」(其模板会被编译成同一作用域内的渲染函数,避免了渲染上下文代理对象) 嗯...這到底是什麼意思,讓我們在下一個小節來深入了解。
嗯...這到底是什麼意思,讓我們在下一個小節來深入了解。
其實這個也不算很重要,但因為我很好奇 again
在上一篇有提到,SFC 檔會從 <template> 和 <script> 中取得內容,編譯出元件的渲染函式。
而 <script> 和 <script setup> 在效能上的差異,就在於渲染函式從 <script> 中取得 <template> 所需變數的方式不同。
<script>+ setup()
setup() 函式和渲染函式會分開宣告,各自形成自己的閉包。
所以,宣告在 setup() 內的變數需要 return 出去,才能傳給渲染函式,在渲染 template 的時候才能取用到所有變數。
<script setup>:不需要經過中間代理,運行時效能比較好。
元件的渲染函式會存在在 setup() 的 scope 內,也就是將渲染函式寫在 setup 的閉包內,最後才回傳出去。
所以,渲染函式可以透過閉包拿到外層 setup 函式 (<script setup>) 內,所有 top-level 變數(包含:變數、函式和 imports),也不用擔心洩漏過多變數或邏輯。

官方文件中有提到,在開發過程中,基於開發工具檢查和模板熱重載的原因,使用 <script setup> 建立的元件,還是會被編譯成回傳物件,而不是直接回傳渲染函式。
也就是說,想看到 <script setup> 和 <script> 差別,要看正式編譯打包後的版本(npm run build)。
「打包出來的程式碼那麼難看,是要看個毛線?」
到 vite.config.js 將 build.minify 設為 false 即可。
// 在 `vite.config.js` 中加入這段
build: {
    minify: false,
}
<scrip setup> 語法糖這麼好用,我們還需要一般的 <script> 嗎?
官方就有提到某些特定情境,只能使用一般 script 才能做到:
name、inheritAttrs或其他插件需要的指定 Option<script> 會在初次載入元件時執行一次,但每次載入元件都會呼叫 setup() hook<script setup> 將所有邏輯都放到 setup() 內,所有每次渲染時都會執行所有程式碼,只想執行一次的程式碼要放在 <script>
在以上情境下,可以在元件內同時使用 <script setup> 和 <script>,如下:
<script>
// normal <script>, executed in module scope (only once)
runSideEffectOnce()
// declare additional options
export default {
  inheritAttrs: false,
  customOptions: {}
}
</script>
<script setup>
// executed in setup() scope (for each instance)
</script>